package edu.cicese.alz;

import com.jgoodies.looks.plastic.PlasticXPLookAndFeel;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

/**
 * Created by: Eduardo Quintana Contreras
 * Date: 24/11/11
 * Time: 04:41 PM
 */
public class FrameDisplay extends JFrame{
	private Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();

	private JPanel pPlot = new JPanel();
	private BufferedImage cachedPlot;
	private int plotWidth, plotHeight = 400;
	private int scale = 5;
	private JScrollPane spPlot;

	private JLabel lblMagnitude, lblAxisX, lblAxisY, lblAxisZ;
	private final Color cAxisX = Color.RED;
	private final Color cAxisY = Color.BLUE;
	private final Color cAxisZ = Color.GREEN;

	public FrameDisplay(ResultSet resultSet){
		try {
			UIManager.setLookAndFeel(new PlasticXPLookAndFeel());
			UIManager.put("Panel.background", Color.WHITE);
			UIManager.put("OptionPane.background", Color.WHITE);
			UIManager.put("TextArea.inactiveBackground", Color.WHITE);
			UIManager.put("ProgressBar.selectionBackground", Color.DARK_GRAY);
			UIManager.put("ProgressBar.selectionForeground", Color.WHITE);
			UIManager.put("ToolTip.background", new Color(229, 244, 255));
			UIManager.put("ToolTip.foreground", Color.DARK_GRAY);
			LineBorder toolTipBorder = new LineBorder(new Color(173, 210, 255), 1);
			UIManager.put("ToolTip.border", toolTipBorder);
			Font tooltipFont = new Font("Segoe UI", Font.BOLD, 12);
			UIManager.put("ToolTip.font", tooltipFont);

			/*UIDefaults defaults = UIManager.getDefaults();
			Enumeration en = defaults.keys();
			while (en.hasMoreElements()) {
				Object key = en.nextElement();
				System.out.println(key + ": " + defaults.get(key));
			}*/
		} catch (UnsupportedLookAndFeelException e) {
			e.printStackTrace();
		}
		setTitle("Data Analysis");
		setSize(969, 485);
		setResizable(false);
		setLayout(null);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Rectangle window = getBounds();
		setLocation((screen.width - window.width) / 2, (screen.height - window.height) / 2);

		initComponents();
//		plot(getMagnitudes(resultSet1));
		plot(getData(resultSet, false));
	}

	public void initComponents() {
		getContentPane().setBackground(Color.WHITE);
		pPlot = new JPanel() {
			public void paintComponent(Graphics g) {
				super.paintComponent(g);
				g.drawImage(cachedPlot, 0, 0, null);
			}
		};
//		pPlot.setBackground(new Color(240, 240, 240));
//		pPlot.setBackground(Color.WHITE);
		pPlot.setLayout(null);
		pPlot.setSize(100, plotHeight);
//		pPlot.setBounds(100, 20, 800, plotHeight);


		spPlot = new JScrollPane(pPlot, JScrollPane.VERTICAL_SCROLLBAR_NEVER,
				JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
//		spPlot.setBorder(BorderFactory.createEmptyBorder());
		spPlot.getVerticalScrollBar().setUnitIncrement(16);
		spPlot.setBounds(100, 20, 800, plotHeight);
		spPlot.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 2));


//		pPlot.setPreferredSize(new Dimension(3000, plotHeight));
//		pPlot.repaint();
//		pPlot.revalidate();

		lblMagnitude = new JLabel("<html><center>Acceleration<br>Magnitude</html>", JLabel.RIGHT);
		lblMagnitude.setBounds(5, 155, 80, 40);


		getContentPane().add(spPlot);
		getContentPane().add(lblMagnitude);

		setVisible(true);
	}

	//TODO: Check when there's no data from the accelerometer.
	//TODO: Check the timestamps, because there's no data all the time.
	public void plot(ArrayList<Double> magnitudes) {
		plotWidth = (int)(magnitudes.size() * 0.5f);

		Graphics2D g2d = (Graphics2D)pPlot.getGraphics();
		BufferedImage tempImg = (BufferedImage)createImage(plotWidth, plotHeight);
		Graphics2D tempG = (Graphics2D)tempImg.getGraphics();

		pPlot.setPreferredSize(new Dimension(plotWidth, plotHeight));

		Color color = Color.BLUE;
		tempG.setColor(color);
		BasicStroke magnitudeStroke = new BasicStroke(0.005f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
		tempG.setStroke(magnitudeStroke);
		double x = 0, lastX = 0, lastY = magnitudes.get(0);
		double lineX, lineY = plotHeight / 2;
		double temp;
		for (Double magnitude : magnitudes) {
//			System.out.println(magnitude);
//			temp = magnitude / 2;
//			temp = Math.abs(magnitude / 2);
//			tempG.draw(new Line2D.Double(lastX, lineY - temp, lastX, lineY + temp));
			tempG.draw(new Line2D.Double(lastX, lastY, lastX + 0.5, magnitude));
			lastY = magnitude;
			lastX += 0.5;
		}

		tempG.dispose();
		g2d.drawImage(tempImg, null, 0, 0);
		cachedPlot = tempImg;

		pPlot.repaint();
		pPlot.revalidate();
	}

	//TODO: Check when there's no data from the accelerometer.
	//TODO: Check the timestamps, because there's no data all the time.
	public void plot(ArrayList<Double>[] data) {
		ArrayList<Double> axisesX = data[0];
		ArrayList<Double> axisesY = data[1];
		ArrayList<Double> axisesZ = data[2];
		ArrayList<Double> magnitudes = data[3];

		float point = 0.05f;

		plotWidth = (int)(magnitudes.size() * point);

		Graphics2D g2d = (Graphics2D)pPlot.getGraphics();
		BufferedImage tempImg = (BufferedImage)createImage(plotWidth, plotHeight);
		Graphics2D tempG = (Graphics2D)tempImg.getGraphics();
		tempG.setColor(Color.WHITE);
		tempG.fillRect(0, 0, plotWidth, plotHeight);

		pPlot.setPreferredSize(new Dimension(plotWidth, plotHeight));

		Color baseLineColor = new Color(230, 230, 230);

//		Color color = Color.BLUE;
//		tempG.setColor(color);
		BasicStroke magnitudeStroke = new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
		BasicStroke baseLineStroke = new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);

		double lastX = 0;
		double y = 50; // axis Y value = zero
		double lastValue = y - axisesX.get(0);
		double newValue;
		tempG.setColor(baseLineColor);
		tempG.setStroke(baseLineStroke);
		tempG.draw(new Line2D.Double(0, y, plotWidth, y));
		tempG.setColor(Color.BLUE);
		tempG.setStroke(magnitudeStroke);
		for (Double axisX : axisesX) {
			newValue = y - axisX;
			tempG.draw(new Line2D.Double(lastX, lastValue, lastX + point, newValue));
			lastValue = newValue;
			lastX += point;
		}

		lastX = 0;
		y = 150;
		lastValue = y - axisesY.get(0);
		tempG.setColor(baseLineColor);
		tempG.setStroke(baseLineStroke);
		tempG.draw(new Line2D.Double(0, y, plotWidth, y));
		tempG.setColor(Color.RED);
		tempG.setStroke(magnitudeStroke);
		for (Double axisY : axisesY) {
			newValue = y - axisY;
			tempG.draw(new Line2D.Double(lastX, lastValue, lastX + point, newValue));
			lastValue = newValue;
			lastX += point;
		}

		lastX = 0;
		y = 250;
		lastValue = y - axisesZ.get(0);
		tempG.setColor(baseLineColor);
		tempG.setStroke(baseLineStroke);
		tempG.draw(new Line2D.Double(0, y, plotWidth, y));
		tempG.setColor(Color.GREEN);
		tempG.setStroke(magnitudeStroke);
		for (Double axisZ : axisesZ) {
			newValue = y - axisZ;
			tempG.draw(new Line2D.Double(lastX, lastValue, lastX + point, newValue));
			lastValue = newValue;
			lastX += point;
		}

		lastX = 0;
		y = 350;
		lastValue = y - magnitudes.get(0);
		tempG.setColor(baseLineColor);
		tempG.setStroke(baseLineStroke);
		tempG.draw(new Line2D.Double(0, y, plotWidth, y));
		tempG.setColor(Color.BLACK);
		tempG.setStroke(magnitudeStroke);
		for (Double magnitude : magnitudes) {
			System.out.println(magnitude);
			newValue = y - magnitude;
			tempG.draw(new Line2D.Double(lastX, lastValue, lastX + point, newValue));
			lastValue = newValue;
			lastX += point;
		}

		tempG.dispose();
		g2d.drawImage(tempImg, null, 0, 0);
		cachedPlot = tempImg;

		pPlot.repaint();
		pPlot.revalidate();
	}

	public ArrayList<Double> getMagnitudes(double[][] axis) {
		ArrayList<Double> magnitudes = new ArrayList<>();
		for (double[] measure : axis) {
			magnitudes.add(scale * Math.sqrt(Math.pow(measure[0], 2) + Math.pow(measure[1], 2) + Math.pow(measure[2], 2)));
		}
		return magnitudes;
	}

	public ArrayList<Double> getMagnitudes(ResultSet resultSet) {
		ArrayList<Double> magnitudes = new ArrayList<>();
		int i = 0;
		double delta, magnitude = 0, lastMagnitude = 0, accel = 0;
		try {
			while (resultSet.next()) {
//				lastMagnitude = magnitude;
				magnitude = Math.sqrt(
								Math.pow(resultSet.getDouble(1), 2) +
								Math.pow(resultSet.getDouble(2), 2) +
								Math.pow(resultSet.getDouble(3), 2));
//				magnitudes.add(scale * Math.sqrt(
//						Math.pow(resultSet1.getDouble(1), 2) +
//								Math.pow(resultSet1.getDouble(2), 2) +
//								Math.pow(resultSet1.getDouble(3) - 10, 2)));
//				delta = magnitude - lastMagnitude;
//				accel = accel * 0.9d + delta;
//				System.out.println("Acceleration: " + accel);
//				System.out.println("Magnitude: " + magnitude);
//				magnitudes.add(accel);
				magnitudes.add(magnitude);
//				System.out.println(magnitudes.get(i++));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return magnitudes;

//		float delta = mAccelCurrent - mAccelLast;
//      mAccel = mAccel * 0.9f + delta;
	}

	@SuppressWarnings({"unchecked"})
	public ArrayList<Double>[] getData(ResultSet resultSet, boolean useScale) {
		if (!useScale) {
			scale = 1;
		}
		ArrayList<Double> magnitudes = new ArrayList<>();
		ArrayList<Double> axisesX = new ArrayList<>();
		ArrayList<Double> axisesY = new ArrayList<>();
		ArrayList<Double> axisesZ = new ArrayList<>();
		double axisX, axisY, axisZ;
		try {
			while (resultSet.next()) {
				axisX = resultSet.getDouble(1);
				axisY = resultSet.getDouble(2);
				axisZ = resultSet.getDouble(3);
				magnitudes.add(Math.sqrt(
								Math.pow(axisX, 2) +
								Math.pow(axisY, 2) +
								Math.pow(axisZ, 2)) * scale);
				axisesX.add(axisX * scale);
				axisesY.add(axisY * scale);
				axisesZ.add(axisZ * scale);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return new ArrayList[]{axisesX, axisesY, axisesZ, magnitudes};

//		float delta = mAccelCurrent - mAccelLast;
//      mAccel = mAccel * 0.9f + delta;
	}

//	public static void main(String[] args) {
//		new FrameDisplay();
//	}
}
